package com.yangcb.workrecord.delayqueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;

/**
 * 延迟队列发送通知
 * <p>
 * 说明：一共5次 第一次不成功等待10分钟，第二次20分钟...50分钟
 * </p>
 *
 * @author yangcb
 * @create 2017-10-26 16:34
 **/
public class Task {

    private static final Logger LOGGER = LoggerFactory.getLogger(Task.class);
    //时间单元：十分钟
    private static final long TIME_UNIT = 10;
    //返回结果
    private static final String RES_SUCCESS = "success";
    private static Task instance = new Task();

    public static Task getInstance() {
        return instance;
    }

    // DelayQueue队列没有大小限制，因此向队列插数据不会阻塞
    // DelayQueue中的元素只有当其指定的延迟时间到了，才能够从队列中获取到该元素。否则线程阻塞
    private static DelayQueue<DelayItem<Pair<String, RetMessage>>> queue = new DelayQueue<DelayItem<Pair<String, RetMessage>>>();

    private Thread taskThread;

    private Task() {
        taskThread = new Thread(new Runnable() {
            @Override
            public void run() {
                execute();
            }
        });
        taskThread.setName("Task Thread");
        taskThread.start();
    }

    private void execute() {

        for (; ; ) {
            try {
                DelayItem<Pair<String, RetMessage>> delayItem = queue.take();
                if (delayItem != null) {
                    //到期处理
                    Pair<String, RetMessage> pair = delayItem.getItem();
                    RetMessage msg = pair.getSecond();
                    if (!msg.isSuccess() && msg.getTimes() <= 5) {
                        HashMap<String, String> paramMap = new HashMap<String, String>();
                        paramMap.put("reqData", msg.getReqData());
                        try {
                            //调用服务响应结果
                            String httpResult = HttpsUtil.getInstance().doPostRetString(msg.getUrl(), null, paramMap);
                            LOGGER.info("第{}次异步回调,返回结果,返回参数：{},响应结果：{}", msg.getTimes(),
                                    paramMap.get("reqData"), RES_SUCCESS.equals(httpResult));
                            if (!RES_SUCCESS.equalsIgnoreCase(httpResult)) {
                                msg.setTimes(msg.getTimes() + 1);
                                msg.setSuccess(false);
                                Task.getInstance().put(pair.getFirst(), msg);
                            }
                        } catch (Exception e) {
                            LOGGER.warn(e.getMessage(), e);
                        }
                    }
                }
            } catch (Exception e) {
                LOGGER.warn(e.getMessage(), e);
            }

        }

    }


    public void put(String key, RetMessage msg) {
        if (queue.contains(key)) {
            queue.remove(key);
        }
        long nanoTime = TIME_UNIT + TimeUnit.NANOSECONDS.convert((msg.getTimes() - 1) * TIME_UNIT, TimeUnit.MINUTES);
        queue.put(new DelayItem<Pair<String, RetMessage>>(new Pair<String, RetMessage>(key, msg), nanoTime));


    }

    public static void main(String[] args) throws Exception {
        String orderNo = System.currentTimeMillis()+"";
        RetMessage msg = new RetMessage("http://www.baidu.com", "a=1&b=2");
        Task.getInstance().put(orderNo, msg);
    }


}
